package com.dyna.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dyna.constants.ModuleErrorCodeConstants;
import com.dyna.core.exception.CustomException;
import com.dyna.core.utils.ObjectUtil;
import com.dyna.core.utils.PageUtil;
import com.dyna.domain.req.PageParam;
import com.dyna.domain.resp.PageResult;
import com.dyna.foundation.domain.entity.SysDictData;
import com.dyna.foundation.domain.entity.SysDictType;
import com.dyna.foundation.domain.form.SysDictTypeSaveForm;
import com.dyna.foundation.domain.req.SysDictDataReq;
import com.dyna.foundation.domain.req.SysDictTypePageReq;
import com.dyna.foundation.domain.req.SysDictTypeReq;
import com.dyna.foundation.domain.resp.SysDictTypeResp;
import com.dyna.mapper.SysDictTypeMapper;
import com.dyna.service.SysDictDataService;
import com.dyna.service.SysDictTypeService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.annotations.VisibleForTesting;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author zhoucaiwang
*/
@Service
@AllArgsConstructor
public class SysDictTypeServiceImpl extends ServiceImpl<SysDictTypeMapper, SysDictType> implements SysDictTypeService {

    @Resource
    @Lazy
    private SysDictDataService dictDataService;

    @Override
    public PageResult<SysDictTypeResp> getDictTypePage(SysDictTypeReq req) {
        PageParam pageParam = PageUtil.getPageParam();
        Page<SysDictTypeResp> selectPage = PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()).doSelectPage(
                () -> baseMapper.querySysDictTypePage(req)
        );
        return new PageResult<>(selectPage.getResult(),selectPage.getTotal());
    }

    @Override
    public Integer addSysDictType(SysDictType sysDictType) {
        sysDictType.setCreateTime(LocalDateTime.now());
        return baseMapper.insert(sysDictType);
    }

    @Override
    public Boolean delSysDictType(Integer dictId) {
        return baseMapper.delSysDictType(dictId);
    }

    @Override
    public Integer editSysDictType(SysDictType sysDictType) {
        return baseMapper.updateById(sysDictType);
    }

    @Override
    public Boolean changeSysDictTypeStatus(Integer dictId, Integer status) {
        return baseMapper.changeSysDictTypeStatus(dictId,status);
    }

    @Override
    public PageResult<SysDictData> getSysDictDataPage(SysDictDataReq req) {
        PageParam pageParam = PageUtil.getPageParam();
        Page<SysDictData> selectPage = PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize()).doSelectPage(
                () -> baseMapper.querySysDictDataPage(req)
        );
        return new PageResult<>(selectPage.getResult(),selectPage.getTotal());
    }

    @Override
    public List<SysDictData> getSysDictDataList(SysDictDataReq req) {
        return baseMapper.querySysDictDataPage(req);
    }

    @Override
    public Boolean addSysDictData(SysDictData sysDictData) {
        sysDictData.setCreateTime(LocalDateTime.now());
        return baseMapper.insertSysDictData(sysDictData);
    }

    @Override
    public Boolean editSysDictData(SysDictData sysDictData) {
        return baseMapper.updateSysDictData(sysDictData);
    }

    @Override
    public Boolean delSysDictData(Integer dictId) {
        return baseMapper.delSysDictData(dictId);
    }

    @Override
    public Boolean changeSysDictDataStatus(Integer dictId, Integer status) {
        return baseMapper.changeSysDictDataStatus(dictId, status);
    }

    @Override
    public Map<String, List<SysDictData>> getBatchSysDictList(List<String> dictTypeList) {
        List<SysDictData> list = baseMapper.queryBatchSysDictList(dictTypeList);
        Map<String, List<SysDictData>> map = list.stream().collect(Collectors.groupingBy(SysDictData::getDictType));
        return map;
    }

    @Override
    public Map<Integer, String> getSysDictDataMapByType(String dictType) {
        List<SysDictData> list = baseMapper.querySysDictDataByType(dictType);
        Map<Integer, String> map = list.stream().collect(Collectors.toMap(SysDictData::getDictId, SysDictData::getDictLabel));
        return map;
    }

    @Override
    public List<SysDictData> getSysDictDataByType(String dictType) {
        return baseMapper.querySysDictDataByType(dictType);
    }

    /********************************************************************************************************/

    @Override
    public PageResult<SysDictTypeResp> getDictTypePage(SysDictTypePageReq pageReqVO) {
        PageResult<SysDictType> pageResult = baseMapper.selectPage(pageReqVO);
        List<SysDictTypeResp> list = pageResult.getList().stream().map(it -> {
            SysDictTypeResp resp = new SysDictTypeResp();
            resp.setId(it.getDictId());
            resp.setName(it.getDictName());
            resp.setType(it.getDictType());
            resp.setStatus(it.getStatus());
            resp.setCreateTime(it.getCreateTime());
            return resp;
        }).collect(Collectors.toList());
        return new PageResult<>(list, pageResult.getTotal());
    }

    @Override
    public Long createDictType(SysDictTypeSaveForm createReqVO) {
        // 校验字典类型的名字的唯一性
        validateDictTypeNameUnique(null, createReqVO.getName());
        // 校验字典类型的类型的唯一性
        validateDictTypeUnique(null, createReqVO.getType());

        // 插入字典类型
        SysDictType dictType = BeanUtil.toBean(createReqVO, SysDictType.class);
        baseMapper.insert(dictType);
        return dictType.getDictId();
    }

    @VisibleForTesting
    void validateDictTypeNameUnique(Long id, String name) {
        SysDictType dictType = baseMapper.selectByName(name);
        if (dictType == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的字典类型
        if (ObjectUtil.isNull(id) || !dictType.getDictId().equals(id)) {
            throw new CustomException(ModuleErrorCodeConstants.DICT_TYPE_NAME_DUPLICATE.getMsg());
        }
    }

    @VisibleForTesting
    void validateDictTypeUnique(Long id, String type) {
        if (StrUtil.isEmpty(type)) {
            return;
        }
        SysDictType dictType = baseMapper.selectByType(type);
        if (dictType == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的字典类型
        if (ObjectUtil.isNull(id) || !dictType.getDictId().equals(id)) {
            throw new CustomException(ModuleErrorCodeConstants.DICT_TYPE_TYPE_DUPLICATE.getMsg());
        }
    }

    @Override
    public void updateDictType(SysDictTypeSaveForm updateReqVO) {
        // 校验自己存在
        validateDictTypeExists(updateReqVO.getId());
        // 校验字典类型的名字的唯一性
        validateDictTypeNameUnique(updateReqVO.getId(), updateReqVO.getName());
        // 校验字典类型的类型的唯一性
        validateDictTypeUnique(updateReqVO.getId(), updateReqVO.getType());

        // 更新字典类型
        SysDictType updateObj = BeanUtil.toBean(updateReqVO, SysDictType.class);
        baseMapper.updateById(updateObj);
    }

    @VisibleForTesting
    SysDictType validateDictTypeExists(Long id) {
        if (id == null) {
            return null;
        }
        SysDictType dictType = baseMapper.selectById(id);
        if (dictType == null) {
            throw new CustomException(ModuleErrorCodeConstants.DICT_TYPE_NOT_EXISTS.getMsg());
        }
        return dictType;
    }

    @Override
    public void deleteDictType(Long id) {
        // 校验是否存在
        SysDictType dictType = validateDictTypeExists(id);
        // 校验是否有字典数据
        if (dictDataService.getDictDataCountByDictType(dictType.getDictType()) > 0) {
            throw new CustomException(ModuleErrorCodeConstants.DICT_TYPE_HAS_CHILDREN.getMsg());
        }
        // 删除字典类型
        baseMapper.deleteById(id);
    }

    @Override
    public SysDictType getDictType(Long id) {
        return baseMapper.selectById(id);
    }

    @Override
    public SysDictType getDictType(String type) {
        return baseMapper.selectByType(type);
    }

    @Override
    public List<SysDictType> getDictTypeList() {
        return baseMapper.selectList();
    }


}




